/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.biz.modular.event.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
import vip.xiaonuo.auth.core.util.StpClientUtil;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.biz.modular.apilog.entity.DevApiLog;
import vip.xiaonuo.biz.modular.apilog.mapper.DevApiGoodsMapper;
import vip.xiaonuo.biz.modular.apilog.mapper.DevApiLogMapper;
import vip.xiaonuo.biz.modular.cabinetdoor.vo.BizCabinetDoorResp;
import vip.xiaonuo.biz.modular.event.entity.BizEvent;
import vip.xiaonuo.biz.modular.event.entity.BizEventConfig;
import vip.xiaonuo.biz.modular.event.mapper.BizEventConfigMapper;
import vip.xiaonuo.biz.modular.event.mapper.BizEventMapper;
import vip.xiaonuo.biz.modular.event.param.ClientUserEventHandleParam;
import vip.xiaonuo.biz.modular.event.param.ClientUserEventPageParam;
import vip.xiaonuo.biz.modular.event.param.EventExcDto;
import vip.xiaonuo.biz.modular.event.param.EventQryDto;
import vip.xiaonuo.biz.modular.event.result.*;
import vip.xiaonuo.biz.modular.event.service.*;
import vip.xiaonuo.biz.modular.event.util.EventActionUtil;
import vip.xiaonuo.biz.modular.goods.result.GoodsPageResult;
import vip.xiaonuo.biz.modular.relation.entity.BizRelation;
import vip.xiaonuo.biz.modular.relation.mapper.BizRelationMapper;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.common.util.AliyunSmsUtil;
import vip.xiaonuo.common.util.CommonDownloadUtil;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.util.*;

/**
 * 事件Service接口实现类
 *
 * @author 古月墨塵
 * @date 2022/12/01 19:29
 **/
@Service
@Transactional
public class BizEventServiceImpl extends ServiceImpl<BizEventMapper, BizEvent> implements BizEventService {

    @Resource
    private DevApiLogMapper devApiLogMapper;

    @Resource
    private BizEventConfigMapper bizEventConfigMapper;

    @Resource
    private BizEventReplaceService bizEventReplaceService;

    @Resource
    private BizEventInvService bizEventInvService;

    @Resource
    private BizEventAuthService bizEventAuthService;

    @Resource
    private BizEventDoorService bizEventDoorService;

    @Resource
    private BizEventGoodsService bizEventGoodsService;

    @Resource
    private BizRelationMapper relationMapper;

    @Resource
    private BizEventWebHookService bizEventWebHookService;

    @Resource
    private DevApiGoodsMapper devApiGoodsMapper;

    @Resource
    private BizEventWeighService bizEventWeighService;

    @Override
    public Page<EventPageResult> page(EventQryDto dto) {
        if (!StpUtil.hasRoleOr("superAdmin", "sysAdmin")) {
            //当前用户
            SaBaseLoginUser saBaseLoginUser = StpLoginUserUtil.getLoginUser();
            dto.setUserId(saBaseLoginUser.getId());
        }
        return this.baseMapper.getPageList(CommonPageRequest.defaultPageForDto(dto), dto);
    }

    @Override
    public void handleForAuth(DevApiLog apiLog) {
        //记录
        bizEventAuthService.recod(apiLog);
        //解析完成日志
        this.analysisCompleted(apiLog.getId());
    }

    @Override
    public void handleForRestart(DevApiLog apiLog) {
        //查询对应配置
        BizEventConfig eventConfig = bizEventConfigMapper.selectById("13");
        BizCabinetDoorResp cabDoorInfo = bizEventReplaceService.getCbaDoorRespForCode(apiLog.getCabinetCode(), apiLog.getCabinetDoorCode());
        if (cabDoorInfo != null) {
            String cabName = bizEventReplaceService.getCabName(apiLog.getCabinetCode());
            String eventDesc = eventConfig.getEventDesc().replace("{{cab}}", cabName);
            //组合实体类
            BizEvent event = BeanUtil.toBean(eventConfig, BizEvent.class);
            event.setApiLogId(apiLog.getId());
            event.setEventConfigId(eventConfig.getId());
            event.setEventTime(apiLog.getEventTime());
            event.setEventDesc(eventDesc);
            event.setEventAction(EventActionUtil.getEventAction(apiLog.getReqType()));
            event.setCabinetGroupId(cabDoorInfo.getCabinetGroupId());
            event.setCabinetId(cabDoorInfo.getCabinetInfoId());
            event.setCabinetDoorId(cabDoorInfo.getId());
            bizEventReplaceService.clearBizEvent(event);
            this.save(event);

            //【邮件+短信】柜门管理员
            bizEventReplaceService.sendEmailForDoorAdmin(event);
            Map<String, String> content = new HashMap<>();
            content.put("cab", cabName);
            bizEventReplaceService.sendSmsForDoorAdmin(event, AliyunSmsUtil.POWER_OFF_RESTART, content);
        }
        //解析完成日志
        this.analysisCompleted(apiLog.getId());
    }

    @Override
    public void handleForManInv(DevApiLog apiLog) {
        //统计在库物品数量
        bizEventInvService.countInCabGoods(apiLog);
        //检查报废物品
        bizEventInvService.checkInCabScraoGoods(apiLog);
        //解析完成日志
        this.analysisCompleted(apiLog.getId());
    }

    @Override
    public void handleForAutoInv(DevApiLog apiLog) {
        //统计在库物品数量
        bizEventInvService.countInCabGoods(apiLog);
        //检查报废物品
        bizEventInvService.checkInCabScraoGoods(apiLog);
        //解析完成日志
        this.analysisCompleted(apiLog.getId());
    }

    @Override
    public void handleOpenDoor(DevApiLog apiLog) {
        //记录开门
        bizEventDoorService.recordOpenDoor(apiLog);
        //处理物品
        bizEventGoodsService.handleGoods(apiLog);
        //解析完成日志
        this.analysisCompleted(apiLog.getId());
    }

    @Override
    public void handleCloseDoor(DevApiLog apiLog) {
        //记录关门
        bizEventDoorService.recordCloseDoor(apiLog);
        //处理物品
        bizEventGoodsService.handleGoods(apiLog);
        //解析完成日志
        this.analysisCompleted(apiLog.getId());
    }

    @Override
    public void handleAmbEvent(DevApiLog apiLog) {
        //处理动作
        bizEventWebHookService.handleAction(apiLog);
        //解析完成日志
        this.analysisCompleted(apiLog.getId());
    }

    /**
     * 日志解析完成
     *
     * @param id
     */
    private void analysisCompleted(String id) {
        DevApiLog entity = new DevApiLog();
        entity.setId(id);
        entity.setDaFlag(1);
        entity.setDaTime(new Date());
        devApiLogMapper.updateById(entity);
    }

    @Override
    public Page<ClientUserEventResp> pageUserEventForClient(ClientUserEventPageParam param) {
        String userId = StpClientUtil.getLoginIdAsString();
        param.setUserId(userId);
        Page<ClientUserEventResp> page = getBaseMapper().pageUserEventForClient(Page.of(param.getCurrent(), param.getSize()), param);
        page.getRecords().forEach(item -> item.setIsAdmin(item.getCabinetGroupAdminUserIds().contains(userId)
                || item.getCabinetInfoAdminUserIds().contains(userId)
                || item.getCabinetDoorAdminUserIds().contains(userId)));
        return page;
    }

    @Override
    public ClientUserEventSummary summaryUserEventForClient() {
        String userId = StpClientUtil.getLoginIdAsString();
        long total = getBaseMapper().countUserEventForClient(userId, null);

        long todo = getBaseMapper().countUserEventForClient(userId, 0);

        long processing = getBaseMapper().countUserEventForClient(userId, 1);

        long handled = getBaseMapper().countUserEventForClient(userId, 2);

        return ClientUserEventSummary.builder().total(total).todo(todo).processing(processing).handled(handled).build();
    }

    @Override
    public ClientUserEventDetail detailUserEventForClient(String id) {
        String userId = StpClientUtil.getLoginIdAsString();
        ClientUserEventDetail detail = getBaseMapper().detailUserEventForClient(userId, id);
        //判断是否柜子管理员
        String cabinetId = detail.getCabinetId();
        String cabinetGroupId = detail.getCabinetGroupId();
        long adminPermCount = relationMapper.selectCount(new LambdaQueryWrapper<BizRelation>()
                .or(q -> q.eq(BizRelation::getCategory, "BIZ_RELATION_CABINET_GROUP_AND_ADMIN_USER")
                        .eq(BizRelation::getObjectId, cabinetGroupId)
                        .eq(BizRelation::getTargetId, userId))
                .or(q -> q.eq(BizRelation::getCategory, "BIZ_RELATION_CABINET_INFO_AND_ADMIN_USER")
                        .eq(BizRelation::getObjectId, cabinetId)
                        .eq(BizRelation::getTargetId, userId)));
        detail.setCabinetAdmin(adminPermCount > 0);
        return detail;
    }

    @Override
    public boolean handleUserEventForClient(ClientUserEventHandleParam param) {
        BizEvent event = new BizEvent();
        event.setId(param.getId());
        event.setProcDesc(param.getProcDesc());
        event.setProcTime(new Date());
        if (param.getClose()) {
            event.setProcStatus(2);
        } else {
            event.setProcStatus(1);
        }
        return updateById(event);
    }

    @Override
    public int handleExcBatch(EventExcDto dto) {
        if (dto.getClose()) {
            dto.setProcStatus(2);
        } else {
            dto.setProcStatus(1);
        }
        return this.baseMapper.handleExcBatch(dto);
    }

    @Override
    public void exportInvGoods(String apiLogId, HttpServletResponse response) {
        File tempFile = null;
        List<EventGoodsExportResult> exportList = new ArrayList<>();
        //获取商品列表
        List<GoodsPageResult> list = devApiGoodsMapper.getResultList(apiLogId);
        for (GoodsPageResult item : list) {
            EventGoodsExportResult exportResult = new EventGoodsExportResult();
            if (item.getUnknownFlag() == 1) {
                exportResult.setGoodsName("未知");
            } else {
                exportResult.setGoodsName(item.getGoodsName());
            }
            exportResult.setGoodsCode(item.getGoodsCode());
            exportResult.setRfidNum(item.getRfidNum());
            exportResult.setStoCabDoor(StrUtil.nullToEmpty(item.getBioCabinetName()) + "-" + StrUtil.nullToEmpty(item.getBioCabinetDoorName()));
            exportResult.setCurCabDoor(StrUtil.nullToEmpty(item.getCurCabinetName()) + "-" + StrUtil.nullToEmpty(item.getCurCabinetDoorName()));
            exportResult.setInCabStauts(this.getGoodsLeaveStauts(item.getLeaveFlag()));
            exportResult.setGoodsStauts(this.getGoodsStauts(item.getState()));

            exportList.add(exportResult);
        }
        String fileName = "盘库报告";
        try {
            Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(fileName, "盘库列表"),
                    EventGoodsExportResult.class, exportList);
            tempFile = FileUtil.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName + ".xls");
            BufferedOutputStream outputStream = FileUtil.getOutputStream(tempFile);
            workbook.write(outputStream);
            outputStream.close();
            CommonDownloadUtil.download(tempFile, response);
        } catch (Exception e) {
            e.printStackTrace();
            throw new CommonException("盘库报告导出失败");
        } finally {
            FileUtil.del(tempFile);
        }
    }

    @Override
    public void handleWeigh(DevApiLog apiLog) {
        //处理称重
        bizEventWeighService.handleWeigh(apiLog);
        //解析完成日志
        this.analysisCompleted(apiLog.getId());
    }

    private String getGoodsStauts(Integer state) {
        switch (state) {
            case 0:
                return "已报废";
            case 1:
                return "启用";
            case 2:
                return "维修中";
            default:
                return "未知";
        }
    }

    private String getGoodsLeaveStauts(Integer state) {
        switch (state) {
            case 0:
                return "在柜";
            case 1:
                return "离柜";
            default:
                return "未知";
        }
    }
}
